/**
 * @file   MyInvocationSecurityMetadataSourceService.java
 * @date   2012-10-23上午10:16:26
 * @author liqing
 */
package com.gzceb.zhgjj.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;

import com.gzceb.zhgjj.security.dao.SysAuthoritiesResourcesDAO;

/**
 * <p>
 * 字符串实用类。
 * </p>
 * 
 * @date 2012-10-23上午10:16:26
 * @author liqing
 * @description 最核心的地方，就是提供某个资源对应的权限定义， 即getAttributes方法返回的结果。
 *              此类在初始化时，应该取到所有资源及其对应角色的定义。
 */
@Service
public class MyInvocationSecurityMetadataSourceService implements
		FilterInvocationSecurityMetadataSource {

	@Autowired
	private SysAuthoritiesResourcesDAO pubAuthoritiesResourcesDao;

	private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

	public MyInvocationSecurityMetadataSourceService() {
		loadResourceDefine();
	}

	private void loadResourceDefine() {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"classpath*:spring/applicationContext.xml");

		SessionFactory sessionFactory = (SessionFactory) context
				.getBean("sessionFactory");

		Session session = sessionFactory.openSession();

		String username = "";
		String sql = "";

		// 在Web服务器启动时，提取系统中的所有权限。
		sql = "select authority_name from sys_authorities";

		List<String> query = session.createSQLQuery(sql).list();

		/*
		 * 应当是资源为key， 权限为value。 资源通常为url， 权限就是那些以ROLE_为前缀的角色。 一个资源可以由多个权限来访问。
		 */
		resourceMap = new HashMap<String, Collection<ConfigAttribute>>();

		for (String auth : query) {
			ConfigAttribute ca = new SecurityConfig(auth);

			List<String> query1 = session
					.createSQLQuery(
							"select b.resource_string "
									+ "from sys_authorities_resources a, sys_resources b, "
									+ "sys_authorities c where a.resource_id = b.resource_id "
									+ "and a.authority_id=c.authority_id and c.authority_name='"
									+ auth + "'").list();

			for (String res : query1) {
				String url = res;

				/*
				 * 判断资源文件和权限的对应关系，如果已经存在相关的资源url，则要通过该url为key提取出权限集合，将权限增加到权限集合中。
				 * sparta
				 */
				if (resourceMap.containsKey(url)) {

					Collection<ConfigAttribute> value = resourceMap.get(url);
					value.add(ca);
					resourceMap.put(url, value);
				} else {
					Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
					atts.add(ca);
					resourceMap.put(url, atts);
				}

			}

		}

	}

	/*
	 * (non-Javadoc) 根据URL，找到相关的权限配置。
	 * 
	 * @see
	 * org.springframework.security.access.SecurityMetadataSource#getAttributes
	 * (java.lang.Object)
	 */
	@Override
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		// TODO Auto-generated method stub
		// object 是一个URL，被用户请求的url。
		String url = ((FilterInvocation) object).getRequestUrl();

		int firstQuestionMarkIndex = url.indexOf("?");

		if (firstQuestionMarkIndex != -1) {
			url = url.substring(0, firstQuestionMarkIndex);
		}

		Iterator<String> ite = resourceMap.keySet().iterator();

		while (ite.hasNext()) {
			String resURL = ite.next();

			//
			if (resURL.equals(url)) {
				return resourceMap.get(resURL);
			}
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.security.access.SecurityMetadataSource#
	 * getAllConfigAttributes()
	 */
	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		// TODO Auto-generated method stub
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.security.access.SecurityMetadataSource#supports(java
	 * .lang.Class)
	 */
	@Override
	public boolean supports(Class<?> clazz) {
		// TODO Auto-generated method stub
		return true;
	}

}
